package MicroGZM.loaders;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;

import org.lwjgl.BufferUtils;

import MicroGZM.mesh.Mesh;
import MicroGZM.utils.ResourceRetriever;

public class OBJLoader
{
	//Vertex data
	private static final String VERTICES = "v";
	private static final String UV = "vt";
	private static final String NORMAL = "vn";
	private static final String SPACE_VERTICES = "vp";
	private static final String NON_RATIONAL_SURFACE_TYPE= "cstype";
	private static final String DEGREE = "deg";
	private static final String BASIS_MATRIX = "bmat";
	private static final String STEP_SIZE = "step";
	
	//Elements
	private static final String POINT = "p";
	private static final String LINE = "l";
	private static final String FACE = "f";
	private static final String CURVE = "curv";
	private static final String CURVE_2D = "curv2";
	private static final String SURFACE = "surf";
	
	//Free-form curve / surface body statments
	private static final String PARAMETER_VALUES = "parm";
	private static final String OUTER_TRIMMING_GROUP = "trim";
	private static final String INNER_TRIMMING_GROUP = "hole";
	private static final String SPECIAL_CURVE = "scurv";
	private static final String SPECIAL_POINT = "sp";
	private static final String END_STATMENT = "end";
	
	//Connectivity between free-form surfaces
	private static final String CONNECT = "con";
	
	//Grouping
	private static final String GROUP_NAME = "g";
	private static final String SMOOTHING_GROUP = "s";
	private static final String MERGING_GROUP = "mg";
	private static final String OBJECT_NAME = "o";
	
	//Display rendering attributes
	private static final String BEVEL_INTERPOLATION = "bevel";
	private static final String COLOR_INTERPOLATION = "c_interp";
	private static final String DISSOLVE_INTERPOLATION = "d_interp";
	private static final String LOD = "lod";
	private static final String MATERIAL_NAME = "usemtl";
	private static final String MATERIAL_LIBRARY = "mtllib";
	private static final String SHADOW_CASTING = "shadow_obj";
	private static final String RAY_TRACING = "trace_obj";
	private static final String CURVE_APPROXIMATION_TECH = "ctech";
	private static final String SURFACE_APPROXIMATION_TECH = "stech";
	
	
	private float[] vertices;
	private float[] textureCoordinates;
	int[] indicesList;
	
	private ArrayList<float[]> verticesList;
	private ArrayList<int[]> verticesIndexList;
	
	private ArrayList<float[]> textureCoordinatesList;
	private ArrayList<int[]> textureCoordinatesIndexList;
	
	
	public OBJLoader()
	{
	}
	
	public void loadFile( String path )
	{
		BufferedReader bufferedReader = null;
		try
		{
			bufferedReader = new BufferedReader(new InputStreamReader(ResourceRetriever.getResourceAsStream(path)));
		} catch (IOException e)
		{
			e.printStackTrace();
		}
		
		verticesList = new ArrayList<float[]>();
		textureCoordinatesList = new ArrayList<float[]>();
		verticesIndexList = new ArrayList<int[]>();
		textureCoordinatesIndexList = new ArrayList<int[]>();
		
		String line = null;
		
		try
		{
			while( (line = bufferedReader.readLine()) != null )
			{				
				getData( line );
			}
			
		}
		catch( IOException e )
		{
			System.out.println(" shit");
		}
		
		setData();
	}
	
	private void getData( String l )
	{
		String[] dataArray = l.split(" ");
		String type = dataArray[0];
		
		if( type.equals( VERTICES ) )addVertices(dataArray);
		else if( type.equals( UV ) ) addTextureCoordinates(dataArray);
		else if( type.equals(FACE) ) addIndices(dataArray);
	}

	private void setData()
	{

		float[] currentLine; 
		
		//VERTEX INDICES
		int counter = 0;
		indicesList = new int[verticesIndexList.size() * 3];
		for( int i = 0; i < verticesIndexList.size(); i++ )
		{
			indicesList[counter] 	= verticesIndexList.get(i)[0];
			indicesList[counter+1] 	= verticesIndexList.get(i)[1];
			indicesList[counter+2] 	= verticesIndexList.get(i)[2];
			counter += 3;
		}

		//VERTEX DATA
		counter = 0;
		vertices = new float[indicesList.length * 3];
		for( int i = 0; i < indicesList.length; i++ )
		{
			currentLine = verticesList.get(indicesList[i]);
			
			vertices[counter] 				= currentLine[0];
			vertices[counter+1] 			= currentLine[1];
			vertices[counter+2] 			= currentLine[2];
			
			counter += 3;
			
		}
		
		//TEXTURE COORDINATES INDICES
		counter = 0;
		indicesList = new int[textureCoordinatesIndexList.size() * 3];
		for( int i = 0; i < textureCoordinatesIndexList.size(); i++ )
		{
			indicesList[counter] 	= textureCoordinatesIndexList.get(i)[0];
			indicesList[counter+1] 	= textureCoordinatesIndexList.get(i)[1];
			indicesList[counter+2] 	= textureCoordinatesIndexList.get(i)[2];
			counter += 3;
		}

		//TEXTURE COORDINATES DATA
		counter = 0;
		textureCoordinates = new float[indicesList.length * 2];
		for( int i = 0; i < indicesList.length; i++ )
		{
			currentLine = textureCoordinatesList.get(indicesList[i]);
			
			textureCoordinates[counter] 			= currentLine[0];
			textureCoordinates[counter+1] 			= currentLine[1];
			
			counter += 2;
		}
	}
	
	private void addVertices( String[] data )
	{
		verticesList.add( new float[] { Float.valueOf(data[1].trim()).floatValue(),
										Float.valueOf(data[2].trim()).floatValue(),
										Float.valueOf(data[3].trim()).floatValue()} );
	}
	
	private void addTextureCoordinates( String[] data )
	{
		textureCoordinatesList.add(new float[]{	Float.valueOf(data[1].trim()).floatValue(),
												Float.valueOf(data[2].trim()).floatValue()});
	}
	
	private void addIndices( String[] data )
	{
		verticesIndexList.add(new int[]{Integer.valueOf(data[1].split("/")[0]) - 1,
										Integer.valueOf(data[2].split("/")[0]) - 1,
										Integer.valueOf(data[3].split("/")[0]) - 1});
		
		
		
		textureCoordinatesIndexList.add(new int[]{	Integer.valueOf(data[1].split("/")[1]) - 1,
													Integer.valueOf(data[2].split("/")[1]) - 1,
													Integer.valueOf(data[3].split("/")[1]) - 1});
	}
	
	public float[] getVertices()
	{
		return vertices;
	}
	
	public float[] getTextureCoordinates()
	{
		return textureCoordinates;
	}
}
